package logic

import (
	"context"
	"github.com/jinzhu/copier"
	"github.com/pkg/errors"
	"im_sys/apps/im/immodels"
	"im_sys/pkg/xerr"

	"im_sys/apps/im/rpc/im"
	"im_sys/apps/im/rpc/internal/svc"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetConversationsLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetConversationsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetConversationsLogic {
	return &GetConversationsLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 获取会话
func (l *GetConversationsLogic) GetConversations(in *im.GetConversationsReq) (*im.GetConversationsResp, error) {
	// todo: add your logic here and delete this line

	// 根据用户id在UserConversation表中查询用户包含的会话列表（该列表中会话的状态是用户视角的数据，比如仅包含已读的数据）
	userConv, err := l.svcCtx.UserConversationModel.FindByUserId(l.ctx, in.UserId)
	if err != nil {
		if errors.Is(err, immodels.ErrNotFound) {
			return &im.GetConversationsResp{}, nil
		}
		return nil, errors.Wrapf(xerr.NewDBErr(), "Find conversation list by user id failed: %v", err)
	}

	var res im.GetConversationsResp
	if err = copier.Copy(&res, userConv); err != nil {
		return nil, errors.Wrapf(xerr.NewInternalServerErr(), "Copy user conversation list failed: %v", err)
	}

	// 根据得到的会话id在Conversation表中查询每个id对应会话的实际信息（包括实际消息数）
	ids := make([]string, 0, len(userConv.ConversationList))
	for _, v := range userConv.ConversationList {
		ids = append(ids, v.ConversationId)
	}
	realRecords, err := l.svcCtx.ConversationModel.ListByConversationIds(l.ctx, ids)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewDBErr(), "Find conversation by conversation ids failed: %v", err)
	} // 查询真实数据（非用户视角的数据）

	// 计算是否存在未读消息
	for _, realRecord := range realRecords { // 遍历真实记录
		cid := realRecord.ConversationId
		userRecord, ok := userConv.ConversationList[cid]
		if !ok {
			// 用户视角的记录中没有该会话，直接跳过
			continue
		}

		// 如果用户读取的消息数量小于真实消息数量，则说明存在未读消息
		if userRecord.Total < realRecord.Total {
			// 将真实结果放入返回结果中
			res.ConversationList[cid].Total = int32(realRecord.Total)
			res.ConversationList[cid].ToRead = int32(realRecord.Total - userRecord.Total)
			res.ConversationList[cid].IsShow = true
		}
	}
	return &res, nil
}
